#ifndef CSERVER_MODULES_H
#define CSERVER_MODULES_H
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <functional>

namespace csrv{
	struct default_roles_type{};
	constexpr default_roles_type default_roles;

	struct SqlArg{
		std::string defaultValue;
		bool hasDefault = false;
		bool defaultIsNull = false;
	};

	struct SqlStatement{
		std::string name;
		std::string origin;
		std::string type;
		std::string sql_nocoll;
		std::vector<std::pair<std::string, SqlArg> > nocoll_args;
		std::string sql_name;
		std::string sql;
		std::vector<std::pair<std::string, SqlArg> > args;
		std::string sql_total_name;
		std::string totalSql;
		std::vector<std::pair<std::string, SqlArg> > argsTotal;
	};

	struct ModuleDef{
		std::string name;
		std::set<std::string> roles;
	};

	using SqlTableType = std::unordered_map<std::string, SqlStatement>;
	using ModuleTableType = std::unordered_map<std::string, ModuleDef>;
	class ModuleRegistry{
	public:
		bool registerModule(ModuleDef&& m);
		static ModuleRegistry& instance();

		ModuleTableType& getTable() {return moduleDefs;}
		const ModuleTableType& getTable() const {return moduleDefs;}
	private:
		ModuleRegistry() = default;
		ModuleRegistry(const ModuleRegistry&) = delete;
		ModuleRegistry& operator=(const ModuleRegistry&) = delete;
		ModuleTableType moduleDefs;
	};

	struct ModuleRegisterHolder{};
	struct ModuleRegister{
		ModuleRegisterHolder commit();
		explicit ModuleRegister(const std::string& name);
		ModuleRegister& operator()(const std::string& role);

		private:
		ModuleDef module;

		ModuleRegister(const ModuleRegister&) = delete;
		ModuleRegister& operator=(const ModuleRegister&) = delete;
	};

	struct RequestContext;
	using RestApiHandler = std::function<void(RequestContext&)>;
	struct RestApiHanlderDef {
		RestApiHandler call;
		std::set<std::string> permitRoles;
	};
	using RestApiTableType = std::unordered_map<std::string, std::unordered_map<std::string, RestApiHanlderDef>>;

	RestApiTableType& GetRestApiTable();
	SqlTableType& GetApiSqlTable();

	struct RestApiAddHelper{
		RestApiAddHelper(std::string m, std::string c, RestApiHandler f, std::set<std::string> roles);
	};

	struct GeneralSimpleApi{
		SqlStatement sql;
		explicit GeneralSimpleApi(const SqlStatement& s);
		void operator()(RequestContext&ctx);
	};
	extern void loadSimpleApis(const std::string& path);
}
#endif // end CSERVER_MODULES_H


